package me.yushuai.wukong.base.service.impl;

import me.yushuai.wukong.base.api.dto.CreateWorkingAreaDTO;
import me.yushuai.wukong.base.api.dto.PagingSearchWorkingArea;
import me.yushuai.wukong.base.api.dto.UpdateWorkingAreaDTO;
import me.yushuai.wukong.base.api.dto.WorkingAreaDTO;
import me.yushuai.wukong.base.convertor.WorkingAreaConvertor;
import me.yushuai.wukong.base.entity.WorkingArea;
import me.yushuai.wukong.base.repository.WorkingAreaRepository;
import me.yushuai.wukong.base.service.WorkingAreaService;
import me.yushuai.wukong.common.dto.PageDTO;
import me.yushuai.wukong.common.exceptin.BizIdNotExistException;
import me.yushuai.wukong.common.exceptin.NotExistException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 工作区业务实现类
 *
 * @author zhoushuai@189.cn
 * @since 2022-09-07
 */
@Service
public class WorkingAreaServiceImpl implements WorkingAreaService {

    public static final String WORKING_AREA_ID_NOT_FOUND = "workingArea.workingAreaId.notFound";

    public static final String WORKING_AREA_CODE_HAS_EXIST = "workingArea.workingAreaCode.HasExist";

    @Autowired
    private WorkingAreaRepository workingAreaRepository;

    @Autowired
    private WorkingAreaConvertor workingAreaConvertor;

    @Override
    public Long createWorkingArea(CreateWorkingAreaDTO dto) throws BizIdNotExistException {
        //1. 检查工作区编码是存在
        final String bizId = dto.getBizId();
        if (this.workingAreaRepository.existsByBizId(bizId)) {
            throw new BizIdNotExistException(bizId, WorkingArea.class);
        }

        //2. 新增工作区
        WorkingArea workingArea = this.workingAreaConvertor.mapToWorkingArea(dto);
        this.workingAreaRepository.save(workingArea);
        return workingArea.getId();
    }

    @Override
    public Long updateWorkingAreaById(UpdateWorkingAreaDTO dto) throws NotExistException {
        //1. 检查工作区是否存在
        WorkingArea workingArea = getWorkingAreaOrThrow(dto.getId());

        //2. 通过工作区编号更新工作区信息
        this.workingAreaConvertor.updateToWorkingArea(dto, workingArea);
        this.workingAreaRepository.save(workingArea);

        return workingArea.getId();
    }

    @Override
    public Long updateWorkingAreaByBizId(UpdateWorkingAreaDTO dto) throws BizIdNotExistException {

        //1. 检查工作区是否存在
        WorkingArea workingArea = getWorkingAreaOrThrow(dto.getBizId());

        //2. 通过工作区编号更新工作区信息
        this.workingAreaConvertor.updateToWorkingArea(dto, workingArea);
        this.workingAreaRepository.save(workingArea);

        return dto.getId();
    }

    @Override
    public void deleteWorkingArea(Long workingAreaId) throws NotExistException {

        //1. 删除工作区记录
        this.workingAreaRepository.deleteById(workingAreaId);
    }

    @Override
    public WorkingAreaDTO findById(Long id) throws NotExistException {
        //1. 通过workingAreaId查询工作区信息
        final WorkingArea workingArea = getWorkingAreaOrThrow(id);

        //3. 返回查询结果
        return this.workingAreaConvertor.mapToWorkingAreaDTO(workingArea);
    }

    @Override
    public WorkingAreaDTO findWorkingAreaByBizId(String bizId) throws BizIdNotExistException {
        //1. 通过workingAreaId查询工作区信息
        final WorkingArea workingArea = getWorkingAreaOrThrow(bizId);

        //3. 返回查询结果
        return this.workingAreaConvertor.mapToWorkingAreaDTO(workingArea);
    }

    @Override
    public PageDTO<WorkingAreaDTO> pagingSearchWorkingArea(PagingSearchWorkingArea pagingSearch) {
        //1. prepare query conditions
        Pageable pageable = PageRequest.of(pagingSearch.getCurrent(), pagingSearch.getSize());
        final Specification<WorkingArea> spec = (root, query, criteriaBuilder) -> {
            final List<Predicate> list = new ArrayList<>();

            final Long workingAreaId = pagingSearch.getWorkingAreaId();
            if (Objects.nonNull(workingAreaId)) {
                list.add(criteriaBuilder.equal(root.get("workingAreaId").as(Long.class), workingAreaId));
            }

            return criteriaBuilder.and(list.toArray(Predicate[]::new));
        };

        //2. 执行查询
        final Page<WorkingArea> workingAreaPage = this.workingAreaRepository.findAll(spec, pageable);

        //3 返回分页数据
        final List<WorkingAreaDTO> list = this.workingAreaConvertor.mapToWorkingAreaDTOList(workingAreaPage.getContent());
        pagingSearch.setTotal(workingAreaPage.getNumberOfElements());
        return PageDTO.of(pagingSearch, list);
    }

    @Override
    public void assertWorkingAreaIdHasExist(Long workingAreaId) throws NotExistException {
        if (!this.workingAreaRepository.existsById(workingAreaId)) {
            throw new NotExistException(workingAreaId, WorkingArea.class);
        }
    }


    //------------------------------private method------------------------------------------

    private WorkingArea getWorkingAreaOrThrow(String bizId) throws BizIdNotExistException {
        return this.workingAreaRepository.findByBizId(bizId)
                .orElseThrow(() -> new BizIdNotExistException(bizId, WorkingArea.class));
    }

    private WorkingArea getWorkingAreaOrThrow(Long id) throws NotExistException {
        return this.workingAreaRepository.findById(id)
                .orElseThrow(() -> new NotExistException(id, WorkingArea.class));
    }
}




